[tools][react][typescript][voice][tts]

VoiceCard β€” Multilingual Voice Introduction Generator

VoiceCard β€” Multilingual Voice Introduction Generator
> A CLI tool that generates self-contained multilingual voice intro components from your TTS provider β€” zero runtime API calls, audio baked in at generation time.

VoiceCard β€” Multilingual Voice Introduction Generator

You give it an API key + config. It gives you a ready component.


What It Actually Is

A CLI tool + generator that takes:

  1. Your TTS provider API key (ElevenLabs, OpenAI, etc.)
  2. A single voice.config.ts file
  3. Your intro text per language (or just one language + auto-translate)

And outputs:

  • A self-contained React component (VoiceCard.tsx) β€” paste into any project
  • A self-contained Svelte component (VoiceCard.svelte) β€” paste into any project
  • Pre-generated audio files (fetched from the API and saved locally)
  • Zero runtime API calls β€” audio is baked in at generation time

The visitor's browser never touches your API key. Never calls any external API. Just plays a local audio file.


The Mental Model

You run:   npx voicecard generate

It does:
  1. Reads voice.config.ts
  2. Calls your TTS API with each language's text
  3. Downloads + saves audio files to /public/voicecard/
  4. Writes VoiceCard.tsx  (React)  ← ready to paste
  5. Writes VoiceCard.svelte        ← ready to paste

You get:   <VoiceCard />  β€” drop it anywhere, works offline

No runtime server. No proxy. No API key exposure. Just static files + a component.


Usage: End-to-End in 4 Steps

Step 1 β€” Install

npm install -g voicecard
# or use without installing:
npx voicecard

Step 2 β€” Create your config

voice.config.ts in your project root:

import { defineConfig } from 'voicecard';

export default defineConfig({
  // --- Who you are ---
  owner: {
    name: 'Enes Yeşil',
    photo: '/images/enes.jpg',   // optional, shown in card UI
  },

  // --- Your TTS provider ---
  provider: {
    name: 'elevenlabs',
    apiKey: process.env.ELEVENLABS_API_KEY,   // from .env β€” never committed
    voiceId: 'your-cloned-voice-id',          // your voice clone ID
  },

  // --- Your intro text ---
  // Option A: Write each language manually
  languages: {
    en: {
      text: `Hi, I'm Enes. I build tools at the intersection of design and engineering.
             I care about making complex things feel simple.`,
      label: 'English',
      flag: 'πŸ‡¬πŸ‡§',
    },
    tr: {
      text: `Merhaba, ben Enes. Tasarım ve mühendisliğin kesişiminde araçlar üretiyorum.
             Karmaşık şeyleri sade hissettirmek benim için ânemli.`,
      label: 'TΓΌrkΓ§e',
      flag: 'πŸ‡ΉπŸ‡·',
    },
    de: {
      text: `Hallo, ich bin Enes. Ich entwickle Tools an der Schnittstelle von Design und Engineering.`,
      label: 'Deutsch',
      flag: 'πŸ‡©πŸ‡ͺ',
    },
  },

  // --- Option B: Write one language, auto-translate the rest ---
  // autoTranslate: {
  //   source: 'en',
  //   targets: ['tr', 'de', 'fr', 'ja', 'zh', 'ar', 'es', 'pt'],
  //   provider: 'deepl',   // or 'openai', 'google'
  //   apiKey: process.env.DEEPL_API_KEY,
  // },

  // --- Output ---
  output: {
    audioDir: 'public/voicecard',           // where audio files are saved
    componentDir: 'src/components',         // where the component is written
    frameworks: ['react', 'svelte'],        // which components to generate
  },

  // --- UI ---
  ui: {
    theme: 'card',                          // 'minimal' | 'card' | 'floating'
    trigger: 'button',                      // 'button' | 'auto'
    defaultLanguage: 'en',
    showTranscript: true,
    showLanguageSwitcher: true,
  },
});

Step 3 β€” Generate

npx voicecard generate

Output in terminal:

βœ“ Fetching audio: en  β†’  public/voicecard/intro-en.mp3   (28KB)
βœ“ Fetching audio: tr  β†’  public/voicecard/intro-tr.mp3   (24KB)
βœ“ Fetching audio: de  β†’  public/voicecard/intro-de.mp3   (31KB)
βœ“ Writing component:  β†’  src/components/VoiceCard.tsx
βœ“ Writing component:  β†’  src/components/VoiceCard.svelte

Done. Drop <VoiceCard /> into your page.

Step 4 β€” Drop it in

React (Next.js, Vite, Remix, etc.):

import VoiceCard from '@/components/VoiceCard';

export default function Hero() {
  return (
    <main>
      <VoiceCard />
      <h1>Enes Yeşil</h1>
    </main>
  );
}

Svelte (SvelteKit, etc.):

<script>
  import VoiceCard from '$lib/components/VoiceCard.svelte';
</script>

<VoiceCard />
<h1>Enes Yeşil</h1>

That's it. No config props to pass. Everything is baked into the generated component.


What the Generated Component Contains

The generated file is fully self-contained and readable. No magic. No opaque blob.

// VoiceCard.tsx β€” generated by voicecard on 2026-03-09
// DO NOT EDIT β€” re-run `npx voicecard generate` to regenerate

const VOICECARD_CONFIG = {
  owner: { name: 'Enes Yeşil', photo: '/images/enes.jpg' },
  defaultLanguage: 'en',
  languages: {
    en: { label: 'English', flag: 'πŸ‡¬πŸ‡§', audio: '/voicecard/intro-en.mp3',
          transcript: 'Hi, I\'m Enes. I build tools...' },
    tr: { label: 'TΓΌrkΓ§e',  flag: 'πŸ‡ΉπŸ‡·', audio: '/voicecard/intro-tr.mp3',
          transcript: 'Merhaba, ben Enes...' },
    de: { label: 'Deutsch', flag: 'πŸ‡©πŸ‡ͺ', audio: '/voicecard/intro-de.mp3',
          transcript: 'Hallo, ich bin Enes...' },
  },
  ui: { theme: 'card', trigger: 'button', showTranscript: true }
};

// ... ~150 lines of clean React component code ...

export default function VoiceCard() { ... }

It's a normal component you can read, fork, and modify. The generator just saves you from writing it.


CLI Commands

# Generate components + audio from config
npx voicecard generate

# Only re-fetch audio (config didn't change, just refreshing voice)
npx voicecard audio

# Only regenerate components (audio already exists, UI tweak)
npx voicecard component

# Preview what would be generated without writing files
npx voicecard generate --dry-run

# Validate your config before running
npx voicecard validate

# List all available TTS providers
npx voicecard providers

# Check which languages support your chosen provider's voice clone
npx voicecard languages --provider elevenlabs

# Interactive setup wizard (for first-time users)
npx voicecard init

Supported TTS Providers

All providers are plug-and-play via the provider.name config key.

Provider Voice Cloning Languages Notes
elevenlabs Yes 32 Best quality for cloned voice
openai No (preset voices) 57 Fast, cheap, great quality
deepgram Yes 36 Good alternative to ElevenLabs
azure Yes (Custom Neural) 140+ Most language coverage
google Yes (Custom Voice) 220+ Max coverage, complex setup
browser No varies Zero cost, no API key needed

You only ever set one provider. The CLI calls that provider's API during generation. At runtime, the visitor's browser just plays MP3 files.


Auto-Translate Feature

If you don't speak 10 languages but want 10 language versions, the autoTranslate block handles it:

autoTranslate: {
  source: 'en',                               // your master language
  targets: ['tr', 'de', 'fr', 'ja', 'zh', 'ar', 'es', 'pt', 'hi', 'ko'],
  provider: 'deepl',                          // translation API
  apiKey: process.env.DEEPL_API_KEY,
  reviewDir: 'voicecard/translations',        // saves translated text for your review
}

What happens:

  1. Translates your English text to all target languages
  2. Saves translation files to reviewDir β€” you review them before generating audio
  3. Once you approve (or edit), run npx voicecard generate to produce audio

The review step is intentional. Auto-translated text for your personal intro can be awkward. You want to catch that before it's spoken in your voice.


Project Structure After Generation

your-project/
β”œβ”€β”€ voice.config.ts                  ← you write this
β”œβ”€β”€ .env                             ← ELEVENLABS_API_KEY=... (gitignored)
β”‚
β”œβ”€β”€ public/
β”‚   └── voicecard/
β”‚       β”œβ”€β”€ intro-en.mp3             ← generated audio files
β”‚       β”œβ”€β”€ intro-tr.mp3
β”‚       └── intro-de.mp3
β”‚
β”œβ”€β”€ voicecard/
β”‚   └── translations/                ← auto-translated text (for review)
β”‚       β”œβ”€β”€ de.txt
β”‚       └── fr.txt
β”‚
└── src/components/
    β”œβ”€β”€ VoiceCard.tsx                ← generated React component
    └── VoiceCard.svelte             ← generated Svelte component

Generated Component: UI Themes

All three themes are included in the generated file. You switch via ui.theme in config then regenerate β€” or just change the theme prop at runtime if you want to toggle it dynamically.

minimal

[ β–Ά Hear my intro ]  πŸ‡¬πŸ‡§ πŸ‡ΉπŸ‡· πŸ‡©πŸ‡ͺ

Play button + language flags. Fits inline anywhere.

card

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  [photo]  Enes Yeşil        β”‚
β”‚           β–Ά Hear my intro   β”‚
β”‚  ════════════               β”‚  ← waveform progress bar
β”‚  πŸ‡¬πŸ‡§ English  πŸ‡ΉπŸ‡· TΓΌrkΓ§e πŸ‡©πŸ‡ͺ β”‚
β”‚  β–Ό Read transcript          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Bio card widget. Good as a hero section element.

floating

                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚ πŸŽ™ Listen β”‚  ← bottom-right corner, always visible
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Non-intrusive. Expands on click to show full card.


Security Model

This is the right way to think about it:

Generation time (YOUR machine):
  voice.config.ts + API key β†’ CLI β†’ API call β†’ MP3 files saved locally

Runtime (visitor's browser):
  HTML page loads β†’ component plays /public/voicecard/intro-en.mp3
  ← zero API calls, zero key exposure, zero external dependencies

Your API key is only used at generation time, on your machine. It's in .env, gitignored. The output files (MP3s + component) contain no keys.

This also means the component works offline, behind a firewall, or anywhere β€” because it's just audio files.


Regeneration Strategy

Audio files are expensive to regenerate (API calls cost money + time). The CLI is smart about this:

npx voicecard generate
# Only fetches audio for languages where text changed since last run
# Compares hash of text content against a lockfile: voicecard.lock.json
# Skips unchanged languages
# Always regenerates components (cheap β€” local operation)

voicecard.lock.json β€” tracks what was generated:

{
  "generated": "2026-03-09T14:22:00Z",
  "provider": "elevenlabs",
  "voiceId": "abc123",
  "hashes": {
    "en": "sha256:a1b2c3...",
    "tr": "sha256:d4e5f6...",
    "de": "sha256:g7h8i9..."
  }
}

Commit voicecard.lock.json and the MP3 files to git. Don't commit voice.config.ts's API key (use env vars).


Accessibility

Hard requirements, not optional:

  • Transcript always available as accessible text (visible or toggle-able)
  • aria-live region announces playback state to screen readers
  • Full keyboard control: Space to play/pause, Escape to stop, Tab through languages
  • No autoplay β€” ever. The trigger: 'auto' config option plays only after a user gesture has occurred on the page
  • Respects prefers-reduced-motion β€” animations disabled, no pulsing waveform
  • Color contrast AA minimum on all themes

npx voicecard init β€” Setup Wizard

For first-time users, the interactive wizard eliminates config guesswork:

$ npx voicecard init

? Which TTS provider do you want to use?
  ❯ ElevenLabs (voice cloning, 32 languages)
    OpenAI TTS (no cloning, 57 languages, cheaper)
    Browser TTS (free, no API key)

? Paste your ElevenLabs API key:  **********************

? Do you have a voice clone, or should we create one?
  ❯ I have a voice clone ID already
    Walk me through creating one

? What frameworks do you need?
  ❯ βœ“ React
    βœ“ Svelte
    β—‹ Vanilla HTML

? Which languages do you want? (space to select)
  ❯ βœ“ English
    βœ“ Turkish
    β—‹ German
    β—‹ French
    β—‹ Japanese
    ...

? Write your intro in English:
  ❯ [text input]

? Auto-translate to selected languages?
  ❯ Yes β€” I'll review translations before generating audio
    No β€” I'll write each language myself

βœ“ Created voice.config.ts
βœ“ Created .env (with your API key)
βœ“ Added voicecard/ and .env to .gitignore

Run `npx voicecard generate` when ready.

Roadmap

v1 β€” Core (what's described above)

  • CLI generator
  • ElevenLabs + OpenAI providers
  • React + Svelte output
  • 3 themes
  • Auto-translate with review step

v2 β€” Studio

  • Browser-based UI to run the generator without a terminal (npx voicecard studio)
  • Drag-and-drop to record your own voice instead of using a TTS API
  • Live preview of the component before generating

v3 β€” Publish

  • npx voicecard publish β€” push audio files to Cloudflare R2 or S3 directly
  • CDN URLs instead of local /public/ paths
  • Version management (keep old audio versions when you update your intro)

Created: March 2026 β€” World of Ideas